# coding=gbk
"""
Created on 2016/7/6 0006

@author: Experiment

@about: SVM on Car Evaluation
"""
import os
import random
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm

PATH_CAR_EVALUATION = os.getcwd() + os.sep + "data" + os.sep + "car_evaluation" + os.sep

DIC_VALUE_BUYING = {"vhigh": 3, "high": 2, "med": 1, "low": 0}
DIC_VALUE_MAINT = {"vhigh": 3, "high": 2, "med": 1, "low": 0}
DIC_VALUE_DOORS = {"5more": 3, "4": 2, "3": 1, "2": 0}
DIC_VALUE_PERSONS = {"more": 2, "4": 1, "2": 0}
DIC_VALUE_LUG_BOOT = {"big": 2, "med": 1, "small": 0}
DIC_VALUE_SAFETY = {"high": 2, "med": 1, "low": 0}
DIC_VALUE_CLASS = {"unacc": 3, "acc": 2, "good": 1, "vgood": 0}


class Expmt01:
    def __init__(self):
        pass

    def getData(self, ratio=0.75):
        data_org = np.loadtxt(PATH_CAR_EVALUATION + "car.data", delimiter=",", dtype=str)
        data_num = self.__toNumber(data_org)
        data_bin = self.__toBin(data_num)
        return self.__toSplit(data_bin, ratio)

    def __toNumber(self, data):
        data_num = np.zeros(data.shape)
        for i in range(data.shape[0]):
            data_num[i, 0] = DIC_VALUE_BUYING[data[i, 0]]
            data_num[i, 1] = DIC_VALUE_MAINT[data[i, 1]]
            data_num[i, 2] = DIC_VALUE_DOORS[data[i, 2]]
            data_num[i, 3] = DIC_VALUE_PERSONS[data[i, 3]]
            data_num[i, 4] = DIC_VALUE_LUG_BOOT[data[i, 4]]
            data_num[i, 5] = DIC_VALUE_SAFETY[data[i, 5]]
            data_num[i, 6] = DIC_VALUE_CLASS[data[i, 6]]
        return data_num

    def __toBin(self, data):
        data_bin = np.zeros((data.shape[0], 13))
        for i in range(data.shape[0]):
            for j in range(data_bin.shape[1]):
                if j == 12:
                    data_bin[i, j] = data[i, -1]
                elif j % 2 == 0:
                    data_bin[i, j] = data[i, j / 2] // 2
                elif j % 2 == 1:
                    data_bin[i, j] = data[i, j / 2] % 2
        return data_bin

    def __toSplit(self, data, ratio):
        dic = {}
        for i in range(data.shape[0]):
            if data[i, -1] not in dic.keys():
                dic[data[i, -1]] = []
            (dic[data[i, -1]]).append(data[i, :])
        train_set, test_set = [], []
        for key in dic.keys():
            random.shuffle(dic[key])
            length = int(len(dic[key]) * ratio)
            train_set.extend((dic[key])[:length])
            test_set.extend((dic[key])[length:])
        random.shuffle(train_set)
        random.shuffle(test_set)
        return np.array(train_set), np.array(test_set)

    def process1(self):
        train_set, test_set = self.getData()
        x_train, y_train = train_set[:, :-1], train_set[:, -1].ravel()
        x_test, y_test = test_set[:, :-1], test_set[:, -1].ravel()
        kernels = ["linear", "poly", "rbf", "sigmoid"]
        strategies = ["ovo", "ovr"]
        clfs = []
        for kernel in kernels:
            for strategy in strategies:
                clfs.append(svm.SVC(kernel=kernel, decision_function_shape=strategy))
        scores = np.zeros(len(kernels) * len(strategies))
        for i, clf in enumerate(clfs):
            clf.fit(x_train, y_train)
            scores[i] = self.__score(clf, x_test, y_test)

        for i, kernel in enumerate(kernels):
            for j, strategy in enumerate(strategies):
                print kernel + "\t\t+\t" + strategy + "\t",
                print scores[i * 2 + j]

    def process2(self):
        train_set, test_set = self.getData()
        x_train, y_train = train_set[:, :-1], train_set[:, -1].ravel()
        x_test, y_test = test_set[:, :-1], test_set[:, -1].ravel()
        degrees = np.arange(1, 6, 1, int)
        scores = np.zeros(degrees.shape[0])
        for i, degree in enumerate(degrees):
            clf = svm.SVC(kernel="linear", degree=degree,decision_function_shape="ovo")
            clf.fit(x_train, y_train)
            scores[i] = self.__score(clf, x_test, y_test)

        plt.title("Linear SVM on different degrees")
        plt.plot(degrees, scores)
        plt.show()

    def __score(self, model, x, y):
        diff = model.predict(x) - y
        count = 0
        for one in diff:
            if one == 0:
                count += 1
        return float(count) / len(diff)


if __name__ == '__main__':
    print "**************start**************\n\n"

    # Expmt01().process1()
    Expmt01().process2()

    print "\n\n**************end**************"
